// Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "dali/test/dali_test_bboxes.h"
#include "dali/pipeline/util/bounding_box.h"

namespace dali {

template <typename ImgType>
class BoxEncoderTest : public GenericBBoxesTest<ImgType> {
 public:
  BoxEncoderTest() {
    CreateCocoObjects();
    CreateCocoAnchors();
  }

 protected:
  TensorList<CPUBackend> boxes_;
  TensorList<CPUBackend> labels_;
  vector<float> anchors_;

  void RunForCocoCpu(const vector<float> &anchors, float criteria, bool offset = false) {
    this->SetBatchSize(coco_batch_size);
    this->SetExternalInputs({{"bboxes", &this->boxes_}, {"labels", &this->labels_}});
    this->AddSingleOp(OpSpec("BoxEncoder")
                          .AddArg("device", "cpu")
                          .AddArg("criteria", criteria)
                          .AddArg("anchors", anchors)
                          .AddArg("offset", offset)
                          .AddArg("scale", 300.0f)
                          .AddArg("stds", std::vector<float>({0.1f, 0.1f, 0.2f, 0.2f}))
                          .AddInput("bboxes", "cpu")
                          .AddInput("labels", "cpu")
                          .AddOutput("encoded_bboxes", "cpu")
                          .AddOutput("encoded_labels", "cpu"));

    dali::DeviceWorkspace ws;
    this->RunOperator(&ws);
    this->CheckAnswersForCocoOnCpu(&ws, offset);
  }

  void RunForCocoGpu(const vector<float> &anchors, float criteria, bool offset = false) {
    this->SetBatchSize(coco_batch_size);
    this->SetExternalInputs({{"bboxes", &this->boxes_}, {"labels", &this->labels_}});
    this->AddSingleOp(OpSpec("BoxEncoder")
                          .AddArg("device", "gpu")
                          .AddArg("criteria", criteria)
                          .AddArg("anchors", anchors)
                          .AddArg("offset", offset)
                          .AddArg("scale", 300.0f)
                          .AddArg("stds", std::vector<float>({0.1f, 0.1f, 0.2f, 0.2f}))
                          .AddInput("bboxes", "gpu")
                          .AddInput("labels", "gpu")
                          .AddOutput("encoded_bboxes", "gpu")
                          .AddOutput("encoded_labels", "gpu"));

    dali::DeviceWorkspace ws;
    this->RunOperator(&ws);
    this->CheckAnswersForCocoOnGpu(&ws, offset);
  }

  const vector<int> coco_object_count = { 9, 7, 3, 6, 12, 31, 31, 32, 13};

  const int coco_batch_size = 9;

  const vector<vector<float>> coco_boxes = {
    {
      0.00800000f, 0.01348684f, 0.46112499f, 1.00000000f,
      0.52606249f, 0.59971493f, 0.62974995f, 0.64885968f,
      0.27350000f, 0.26585528f, 0.30095309f, 0.43789473f,
      0.27260938f, 0.08747807f, 0.62365627f, 1.00000000f,
      0.61110938f, 0.58271933f, 0.81009370f, 0.78265357f,
      0.82784379f, 0.88201755f, 0.90031254f, 1.00000000f,
      0.53293747f, 0.89311403f, 0.60610932f, 1.00000000f,
      0.63068753f, 0.82796049f, 0.69424999f, 0.91853064f,
      0.70648438f, 0.93995613f, 0.78620309f, 1.00000000f,
    },
    {
      0.10112500f, 0.21797222f, 0.88735944f, 0.77077770f,
      0.98060942f, 0.40358332f, 0.99967194f, 0.44494441f,
      0.46729690f, 0.43291667f, 0.49932814f, 0.51297224f,
      0.90595311f, 0.44258335f, 0.91853124f, 0.47866669f,
      0.77206248f, 0.00000000f, 0.81173438f, 0.08411111f,
      0.96995318f, 0.42811111f, 1.00000000f, 0.56316662f,
      0.88803130f, 0.46908331f, 0.98442191f, 0.58394444f,
    },
    {
      0.49365625f, 0.16355971f, 0.72104686f, 0.82276350f,
      0.29301563f, 0.13063231f, 0.56199998f, 0.87838411f,
      0.01050000f, 0.51911008f, 0.71517187f, 0.85843086f,
    },
    {
      0.62010938f, 0.70079625f, 0.71157813f, 0.94072598f,
      0.37431249f, 0.22718970f, 0.56432807f, 0.71327871f,
      0.51875001f, 0.20224825f, 0.67918748f, 0.69213110f,
      0.26292187f, 0.22128806f, 0.37992185f, 0.71955502f,
      0.42656249f, 0.42451993f, 0.68387496f, 0.67292738f,
      0.28239062f, 0.43517566f, 0.38075000f, 0.71091336f,
    },
    {
      0.59298438f, 0.02085417f, 0.63339061f, 0.07797917f,
      0.26890627f, 0.68112499f, 0.33731252f, 0.93589586f,
      0.56020314f, 0.81085414f, 0.58603126f, 0.85004163f,
      0.60403121f, 0.50581247f, 0.77684373f, 1.00000000f,
      0.81912500f, 0.53100002f, 0.84993744f, 0.62874997f,
      0.41203126f, 0.75597918f, 0.44129691f, 0.84412497f,
      0.16723438f, 0.74318755f, 0.18379687f, 0.81364590f,
      0.34514064f, 0.77364582f, 0.35848436f, 0.80477083f,
      0.12693749f, 0.75250000f, 0.14856251f, 0.82539582f,
      0.40528125f, 0.78072917f, 0.42240626f, 0.83114588f,
      0.27746874f, 0.75468749f, 0.28779688f, 0.78164583f,
      0.38251561f, 0.76122922f, 0.40823436f, 0.84666669f
    },
    {
      0.57246876f, 0.38765809f, 0.72946876f, 0.67824352f,
      0.74407810f, 0.31817329f, 0.88279688f, 0.68320841f,
      0.66740626f, 0.28597191f, 0.69807816f, 0.40032786f,
      0.49968749f, 0.23430914f, 0.64314061f, 0.64976585f,
      0.19607812f, 0.28414521f, 0.23143749f, 0.46583140f,
      0.06339063f, 0.28192037f, 0.11528125f, 0.44564405f,
      0.56248438f, 0.15718970f, 0.57948434f, 0.20255271f,
      0.72037500f, 0.14213115f, 0.73446876f, 0.19409835f,
      0.40095311f, 0.44283372f, 0.50051558f, 0.48498827f,
      0.57028127f, 0.56540984f, 0.59790623f, 0.64491802f,
      0.65201563f, 0.22498830f, 0.66979688f, 0.26285714f,
      0.92539060f, 0.26103044f, 0.94442189f, 0.28814989f,
      0.79640627f, 0.25337237f, 0.80529690f, 0.26309136f,
      0.77565628f, 0.23316158f, 0.78642190f, 0.24093676f,
      0.89512503f, 0.17503512f, 0.90620315f, 0.18358314f,
      0.84935939f, 0.21025760f, 0.86035937f, 0.21728337f,
      0.73206246f, 0.24559720f, 0.74314058f, 0.25327870f,
      0.78985941f, 0.13922717f, 0.81229687f, 0.19754098f,
      0.09215625f, 0.36206090f, 0.10650001f, 0.38245904f,
      0.79162502f, 0.20526932f, 0.80279696f, 0.21149884f,
      0.79767191f, 0.23491803f, 0.80925000f, 0.24032785f,
      0.79928124f, 0.24829039f, 0.81371880f, 0.26030442f,
      0.62948436f, 0.20941451f, 0.64243752f, 0.21704918f,
      0.81332815f, 0.24887587f, 0.82639062f, 0.25896955f,
      0.67890626f, 0.25555035f, 0.68965626f, 0.26131147f,
      0.66379684f, 0.25517565f, 0.67907810f, 0.26320842f,
      0.38343748f, 0.32597190f, 0.43020311f, 0.43351290f,
      0.84996873f, 0.22974238f, 0.86323434f, 0.23754099f,
      0.73079687f, 0.15667447f, 0.74601561f, 0.19344261f,
      0.00156250f, 0.07494145f, 0.99843752f, 0.69789225f,
      0.47968751f, 0.11241218f, 0.99843752f, 0.34660423f
    },
    {
      0.71629685f, 0.32360417f, 0.87471879f, 0.65393752f,
      0.70990622f, 0.31389582f, 0.78492188f, 0.47006252f,
      0.14273438f, 0.37500000f, 0.38935938f, 0.60247916f,
      0.15918750f, 0.35099998f, 0.24153125f, 0.53281248f,
      0.41798440f, 0.37304166f, 0.48539066f, 0.54606247f,
      0.10987500f, 0.39658335f, 0.16096875f, 0.48175001f,
      0.32965624f, 0.36543751f, 0.38968748f, 0.50812501f,
      0.39539063f, 0.35456249f, 0.45831251f, 0.54945832f,
      0.49079686f, 0.37416667f, 0.53024995f, 0.47404167f,
      0.52634370f, 0.37958333f, 0.56759369f, 0.46977082f,
      0.88692188f, 0.36931249f, 0.92875004f, 0.44170836f,
      0.44759375f, 0.43147916f, 0.48324999f, 0.49652085f,
      0.92403126f, 0.36729166f, 1.00000000f, 0.53504169f,
      0.00000000f, 0.01493750f, 0.49524999f, 0.29247916f,
      0.27739063f, 0.26947919f, 0.44289064f, 0.34075001f,
      0.25512499f, 0.33122918f, 0.41171876f, 0.37739584f,
      0.46284375f, 0.23810416f, 0.80645311f, 0.37693748f,
      0.75371873f, 0.19391666f, 1.00000000f, 0.34364587f,
      0.77712500f, 0.00000000f, 1.00000000f, 0.17929167f,
      0.39020312f, 0.31564581f, 0.48740625f, 0.39279166f,
      0.39684373f, 0.04575000f, 0.87087500f, 0.54729170f,
      0.68220311f, 0.32889584f, 0.75860935f, 0.36679167f,
      0.00000000f, 0.24652083f, 0.29067189f, 0.47408333f,
      0.95273435f, 0.24116667f, 1.00000000f, 0.29925001f,
      0.86460936f, 0.38841668f, 0.88828123f, 0.43014583f,
      0.89125001f, 0.39270833f, 0.90178126f, 0.43304166f,
      0.86751568f, 0.49218750f, 0.99115628f, 0.54779166f,
      0.00798438f, 0.43764585f, 0.09537500f, 0.54366672f,
      0.03526562f, 0.34575000f, 0.18789062f, 0.39210418f,
      0.93485940f, 0.56433332f, 0.95479691f, 0.58795834f,
      0.00000000f, 0.34583333f, 0.99843752f, 0.51875001f
    },
    {
      0.49457812f, 0.41158018f, 0.55237496f, 0.54056603f,
      0.59578121f, 0.10084905f, 0.60809374f, 0.16193396f,
      0.58496875f, 0.10797170f, 0.59398437f, 0.15872642f,
      0.60907811f, 0.10209906f, 0.62053120f, 0.14943397f,
      0.56648433f, 0.10933962f, 0.58018744f, 0.16646227f,
      0.57209378f, 0.21721698f, 0.76328123f, 0.73846692f,
      0.35106248f, 0.38893870f, 0.42285937f, 0.44294810f,
      0.01446875f, 0.42808962f, 0.09973438f, 0.50667447f,
      0.63701564f, 0.09011792f, 0.65440625f, 0.13931604f,
      0.49754685f, 0.14688680f, 0.50898439f, 0.19747640f,
      0.49382812f, 0.37681603f, 0.50142181f, 0.43301889f,
      0.52260935f, 0.15214624f, 0.53610939f, 0.18610850f,
      0.62157810f, 0.07389151f, 0.63831246f, 0.14049529f,
      0.53970313f, 0.16037735f, 0.54793751f, 0.17974056f,
      0.43618751f, 0.16653302f, 0.45289063f, 0.20391509f,
      0.01742188f, 0.03191038f, 0.04206250f, 0.08167453f,
      0.39303124f, 0.47641510f, 0.61039060f, 0.90785378f,
      0.27690625f, 0.43370283f, 0.37814063f, 0.46516508f,
      0.42045313f, 0.16061321f, 0.43843752f, 0.19905660f,
      0.54495311f, 0.13179246f, 0.55818748f, 0.17754717f,
      0.51720315f, 0.14634433f, 0.52417189f, 0.18903302f,
      0.52048433f, 0.15146227f, 0.53364062f, 0.18577830f,
      0.12940624f, 0.03966981f, 0.14932813f, 0.11339623f,
      0.55078125f, 0.11976415f, 0.56645310f, 0.16898586f,
      0.48785940f, 0.17919812f, 0.49675003f, 0.20009434f,
      0.55392188f, 0.14806603f, 0.55901563f, 0.17018867f,
      0.54860938f, 0.46679243f, 0.57192189f, 0.52346694f,
      0.52496874f, 0.37799528f, 0.52921879f, 0.40221700f,
      0.50050002f, 0.38153303f, 0.50865626f, 0.41221699f,
      0.46831250f, 0.15688679f, 0.48098436f, 0.20509434f,
      0.45120311f, 0.17066038f, 0.46270308f, 0.20226416f,
      0.57343751f, 0.11084906f, 0.59218752f, 0.17452830f
    },
    {
      0.53139061f, 0.71385592f, 0.56545311f, 0.80402541f,
      0.05510937f, 0.24944915f, 0.12198438f, 0.39847454f,
      0.61509377f, 0.29686439f, 0.63782811f, 0.39466101f,
      0.40935937f, 0.14605933f, 0.51045310f, 0.76402539f,
      0.48529688f, 0.22097458f, 0.60281247f, 0.76550847f,
      0.00029687f, 0.08923729f, 0.09062500f, 0.86067796f,
      0.60940623f, 0.23368645f, 0.72406250f, 0.76868647f,
      0.95212495f, 0.15504238f, 0.99770308f, 0.89211863f,
      0.07971875f, 0.20508476f, 0.20081250f, 0.90923721f,
      0.58078128f, 0.24423729f, 0.61543751f, 0.39046606f,
      0.59234375f, 0.33648306f, 0.61023438f, 0.37406781f,
      0.76204687f, 0.12372882f, 0.82492191f, 0.63614410f,
      0.10334375f, 0.23364407f, 0.11985938f, 0.26415256f
    }
  };

  const vector<vector<int>> coco_labels = {
    { 1, 44, 28, 1, 56, 56, 56, 56, 56, },
    { 6, 1, 12, 1, 1, 1, 59, },
    { 1, 1, 38, },
    { 17, 1, 1, 1, 14, 14, },
    { 33, 1, 1, 1, 1, 1, 1, 1, 1, 57, 1, 1 },
    { 1, 1, 1, 1, 1, 1, 1, 1, 35, 36, 1, 1, 57, 57, 57, 57, 57, 1, 36, 57,
      57, 57, 57, 57, 57, 57, 1, 57, 1, 57, 1 },
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 1, 26, 26, 26, 26, 26, 26, 26,
      26, 26, 26, 26, 27, 27, 48, 1, 26, 48, 1},
    { 59, 40, 40, 40, 40, 73, 69, 71, 40, 40, 40, 40, 40, 41, 41, 41, 61,
      72, 41, 41, 41, 41, 41, 41, 41, 41, 70, 40, 40, 40, 42, 40},
    { 33, 3, 57, 1, 1, 1, 1, 1, 1, 1, 57, 1, 1}
  };

  void CreateCocoObjects() {
    TensorListShape<> boxes_shape(coco_object_count.size(), 2);
    TensorListShape<> labels_shape(coco_object_count.size(), 1);
    for (size_t i = 0; i < coco_object_count.size(); i++) {
      boxes_shape.set_tensor_shape(i, {coco_object_count[i], 4});
      labels_shape.set_tensor_shape(i, {coco_object_count[i]});
    }

    boxes_.Resize(boxes_shape);

    for (int sample = 0; sample < coco_batch_size; ++sample) {
      auto boxes_data = boxes_.mutable_tensor<float>(sample);
      MemCopy(
        boxes_data,
        coco_boxes[sample].data(),
        coco_object_count[sample] * 4 * sizeof(float));

      labels_.Resize(labels_shape);
      auto labels_data = labels_.mutable_tensor<int>(sample);
      MemCopy(labels_data, coco_labels[sample].data(), coco_object_count[sample] * sizeof(int));
    }
  }

  // Expected matches : <idx of matched anchor, <matched object, matched object class>>
  const vector<vector<std::pair<int, std::pair<float4, int>>>> coco_matches = {
    {
      {895, {{0.5779062510f, 0.6242873073f, 0.1036874652f, 0.0491447449f}, 44}},
      {1240, {{0.6624687910f, 0.8732455969f, 0.0635624528f, 0.0905701518f}, 56}},
      {1324, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {1351, {{0.5695233941f, 0.9465570450f, 0.0731718540f, 0.1068859696f}, 56}},
      {1362, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {1395, {{0.7463437319f, 0.9699780941f, 0.0797187090f, 0.0600438714f}, 56}},
      {1396, {{0.7463437319f, 0.9699780941f, 0.0797187090f, 0.0600438714f}, 56}},
      {2684, {{0.6624687910f, 0.8732455969f, 0.0635624528f, 0.0905701518f}, 56}},
      {2685, {{0.6624687910f, 0.8732455969f, 0.0635624528f, 0.0905701518f}, 56}},
      {2768, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {2794, {{0.5695233941f, 0.9465570450f, 0.0731718540f, 0.1068859696f}, 56}},
      {2795, {{0.5695233941f, 0.9465570450f, 0.0731718540f, 0.1068859696f}, 56}},
      {2805, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {2806, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {3783, {{0.5779062510f, 0.6242873073f, 0.1036874652f, 0.0491447449f}, 44}},
      {3784, {{0.5779062510f, 0.6242873073f, 0.1036874652f, 0.0491447449f}, 44}},
      {4283, {{0.7463437319f, 0.9699780941f, 0.0797187090f, 0.0600438714f}, 56}},
      {4284, {{0.7463437319f, 0.9699780941f, 0.0797187090f, 0.0600438714f}, 56}},
      {4874, {{0.2872265577f, 0.3518750072f, 0.0274530947f, 0.1720394492f}, 28}},
      {5572, {{0.6624687910f, 0.8732455969f, 0.0635624528f, 0.0905701518f}, 56}},
      {5683, {{0.5695233941f, 0.9465570450f, 0.0731718540f, 0.1068859696f}, 56}},
      {5694, {{0.8640781641f, 0.9410088062f, 0.0724687576f, 0.1179824471f}, 56}},
      {6017, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {6377, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {6378, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {6397, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {6739, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {6758, {{0.7106015682f, 0.6826864481f, 0.1989843249f, 0.1999342442f}, 56}},
      {8629, {{0.4481328130f, 0.5437390208f, 0.3510468900f, 0.9125219584f}, 1}},
      {8678, {{0.2345624864f, 0.5067434311f, 0.4531250000f, 0.9865131378f}, 1}},
      {8679, {{0.4481328130f, 0.5437390208f, 0.3510468900f, 0.9125219584f}, 1}},
      {8695, {{0.2345624864f, 0.5067434311f, 0.4531250000f, 0.9865131378f}, 1}},
      {8704, {{0.2345624864f, 0.5067434311f, 0.4531250000f, 0.9865131378f}, 1}},
      {8722, {{0.2345624864f, 0.5067434311f, 0.4531250000f, 0.9865131378f}, 1}},
      {8723, {{0.4481328130f, 0.5437390208f, 0.3510468900f, 0.9125219584f}, 1}},
      {8731, {{0.4481328130f, 0.5437390208f, 0.3510468900f, 0.9125219584f}, 1}},
    },
    {
      {67, {{0.7918984294f, 0.0420555547f, 0.0396718979f, 0.0841111094f}, 1}},
      {2200, {{0.9362266064f, 0.5265138745f, 0.0963906050f, 0.1148611307f}, 59}},
      {2201, {{0.9362266064f, 0.5265138745f, 0.0963906050f, 0.1148611307f}, 59}},
      {2238, {{0.9362266064f, 0.5265138745f, 0.0963906050f, 0.1148611307f}, 59}},
      {2239, {{0.9362266064f, 0.5265138745f, 0.0963906050f, 0.1148611307f}, 59}},
      {4399, {{0.7918984294f, 0.0420555547f, 0.0396718979f, 0.0841111094f}, 1}},
      {4977, {{0.9901406765f, 0.4242638648f, 0.0190625191f, 0.0413610935f}, 1}},
      {4996, {{0.4833125174f, 0.4729444385f, 0.0320312381f, 0.0800555646f}, 12}},
      {5012, {{0.9122421741f, 0.4606250226f, 0.0125781298f, 0.0360833406f}, 1}},
      {5052, {{0.9849765897f, 0.4956388474f, 0.0300468206f, 0.1350555122f}, 1}},
      {8553, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8554, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8578, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8579, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8604, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8696, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8705, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8714, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8728, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
      {8730, {{0.4942422211f, 0.4943749607f, 0.7862344384f, 0.5528054833f}, 6}},
    },
    {
      {8104, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8105, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8106, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8277, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8287, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8297, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8477, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8486, {{0.4275078177f, 0.5045081973f, 0.2689843476f, 0.7477518320f}, 1}},
      {8487, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8497, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8558, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8583, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8608, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
      {8629, {{0.6073515415f, 0.4931616187f, 0.2273906171f, 0.6592037678f}, 1}},
      {8658, {{0.3628359437f, 0.6887704730f, 0.7046718597f, 0.3393207788f}, 38}},
    },
    {
      {6318, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {6336, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {6337, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {6338, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {6356, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {7055, {{0.3315703273f, 0.5730445385f, 0.0983593762f, 0.2757377028f}, 14}},
      {7074, {{0.3315703273f, 0.5730445385f, 0.0983593762f, 0.2757377028f}, 14}},
      {7137, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7156, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7175, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7777, {{0.3315703273f, 0.5730445385f, 0.0983593762f, 0.2757377028f}, 14}},
      {7796, {{0.3315703273f, 0.5730445385f, 0.0983593762f, 0.2757377028f}, 14}},
      {7859, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7878, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7897, {{0.6658437252f, 0.8207610846f, 0.0914687514f, 0.2399297357f}, 17}},
      {7997, {{0.5552186966f, 0.5487236381f, 0.2573124766f, 0.2484074533f}, 14}},
      {8276, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8277, {{0.5989687443f, 0.4471896887f, 0.1604374647f, 0.4898828566f}, 1}},
      {8284, {{0.3214218616f, 0.4704215527f, 0.1169999838f, 0.4982669652f}, 1}},
      {8286, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8287, {{0.5989687443f, 0.4471896887f, 0.1604374647f, 0.4898828566f}, 1}},
      {8296, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8476, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8477, {{0.5989687443f, 0.4471896887f, 0.1604374647f, 0.4898828566f}, 1}},
      {8486, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8487, {{0.5989687443f, 0.4471896887f, 0.1604374647f, 0.4898828566f}, 1}},
      {8496, {{0.4693202972f, 0.4702342153f, 0.1900155842f, 0.4860889912f}, 1}},
      {8497, {{0.5989687443f, 0.4471896887f, 0.1604374647f, 0.4898828566f}, 1}},
    },
    {
      {61, {{0.6131874919f, 0.0494166687f, 0.0404062271f, 0.0571250021f}, 33}},
      {3962, {{0.2826328278f, 0.7681666613f, 0.0103281438f, 0.0269583464f}, 1}},
      {5161, {{0.8345311880f, 0.5798749924f, 0.0308124423f, 0.0977499485f}, 1}},
      {5439, {{0.1377499998f, 0.7889479399f, 0.0216250122f, 0.0728958249f}, 1}},
      {5440, {{0.1755156219f, 0.7784167528f, 0.0165624917f, 0.0704583526f}, 1}},
      {5485, {{0.3518124819f, 0.7892082930f, 0.0133437216f, 0.0311250091f}, 1}},
      {5486, {{0.3953749835f, 0.8039479256f, 0.0257187486f, 0.0854374766f}, 1}},
      {5487, {{0.4138437510f, 0.8059375286f, 0.0171250105f, 0.0504167080f}, 57}},
      {5531, {{0.5731171966f, 0.8304479122f, 0.0258281231f, 0.0391874909f}, 1}},
      {7130, {{0.3031094074f, 0.8085104227f, 0.0684062541f, 0.2547708750f}, 1}},
      {7149, {{0.3031094074f, 0.8085104227f, 0.0684062541f, 0.2547708750f}, 1}},
      {7852, {{0.3031094074f, 0.8085104227f, 0.0684062541f, 0.2547708750f}, 1}},
      {7871, {{0.3031094074f, 0.8085104227f, 0.0684062541f, 0.2547708750f}, 1}},
      {8308, {{0.6904374361f, 0.7529062033f, 0.1728125215f, 0.4941875339f}, 1}},
      {8318, {{0.6904374361f, 0.7529062033f, 0.1728125215f, 0.4941875339f}, 1}},
      {8508, {{0.6904374361f, 0.7529062033f, 0.1728125215f, 0.4941875339f}, 1}},
      {8518, {{0.6904374361f, 0.7529062033f, 0.1728125215f, 0.4941875339f}, 1}},
      {8528, {{0.6904374361f, 0.7529062033f, 0.1728125215f, 0.4941875339f}, 1}},
    },
    {
      {535, {{0.0993281305f, 0.3722599745f, 0.0143437609f, 0.0203981400f}, 36}},
      {3550, {{0.4507343471f, 0.4639109969f, 0.0995624661f, 0.0421545506f}, 35}},
      {3551, {{0.4507343471f, 0.4639109969f, 0.0995624661f, 0.0421545506f}, 35}},
      {4587, {{0.7274218798f, 0.1681147516f, 0.0140937567f, 0.0519672036f}, 1}},
      {4590, {{0.8010781407f, 0.1683840752f, 0.0224374533f, 0.0583138168f}, 1}},
      {4619, {{0.5709843636f, 0.1798712015f, 0.0169999599f, 0.0453630090f}, 1}},
      {4625, {{0.7384062409f, 0.1750585437f, 0.0152187347f, 0.0367681384f}, 1}},
      {4631, {{0.9006640911f, 0.1793091297f, 0.0110781193f, 0.0085480213f}, 57}},
      {4660, {{0.6359609365f, 0.2132318467f, 0.0129531622f, 0.0076346695f}, 57}},
      {4661, {{0.6714375019f, 0.2591920495f, 0.0152812600f, 0.0080327690f}, 57}},
      {4663, {{0.7376015186f, 0.2494379580f, 0.0110781193f, 0.0076815039f}, 57}},
      {4665, {{0.7810391188f, 0.2370491624f, 0.0107656121f, 0.0077751726f}, 57}},
      {4666, {{0.8198593855f, 0.2539227009f, 0.0130624771f, 0.0100936741f}, 57}},
      {4668, {{0.8566015363f, 0.2336416841f, 0.0132656097f, 0.0077986121f}, 57}},
      {4747, {{0.9349062443f, 0.2745901644f, 0.0190312862f, 0.0271194577f}, 1}},
      {4791, {{0.0893359333f, 0.3637822270f, 0.0518906191f, 0.1637236774f}, 1}},
      {4813, {{0.6827422380f, 0.3431499004f, 0.0306718946f, 0.1143559515f}, 1}},
      {4829, {{0.0893359333f, 0.3637822270f, 0.0518906191f, 0.1637236774f}, 1}},
      {4841, {{0.4068202972f, 0.3797423840f, 0.0467656255f, 0.1075409949f}, 1}},
      {4867, {{0.0893359333f, 0.3637822270f, 0.0518906191f, 0.1637236774f}, 1}},
      {4879, {{0.4068202972f, 0.3797423840f, 0.0467656255f, 0.1075409949f}, 1}},
      {4910, {{0.2137578130f, 0.3749883175f, 0.0353593677f, 0.1816861928f}, 1}},
      {5189, {{0.5840937495f, 0.6051639318f, 0.0276249647f, 0.0795081854f}, 36}},
      {6319, {{0.6509687901f, 0.5329508185f, 0.1570000052f, 0.2905854285f}, 1}},
      {6320, {{0.6509687901f, 0.5329508185f, 0.1570000052f, 0.2905854285f}, 1}},
      {6338, {{0.6509687901f, 0.5329508185f, 0.1570000052f, 0.2905854285f}, 1}},
      {6339, {{0.6509687901f, 0.5329508185f, 0.1570000052f, 0.2905854285f}, 1}},
      {7968, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {7969, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {8168, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {8169, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {8287, {{0.5714140534f, 0.4420374930f, 0.1434531212f, 0.4154567122f}, 1}},
      {8289, {{0.8134374619f, 0.5006908178f, 0.1387187839f, 0.3650351167f}, 1}},
      {8368, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {8369, {{0.7390625477f, 0.2295082062f, 0.5187500119f, 0.2341920435f}, 1}},
      {8477, {{0.5714140534f, 0.4420374930f, 0.1434531212f, 0.4154567122f}, 1}},
      {8487, {{0.5714140534f, 0.4420374930f, 0.1434531212f, 0.4154567122f}, 1}},
      {8696, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
      {8705, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
      {8714, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
      {8728, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
      {8729, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
      {8730, {{0.5000000000f, 0.3864168525f, 0.9968750477f, 0.6229507923f}, 57}},
    },
    {
      {416, {{0.9763671756f, 0.2702083290f, 0.0472656488f, 0.0580833405f}, 26}},
      {510, {{0.4388046861f, 0.3542187214f, 0.0972031355f, 0.0771458447f}, 26}},
      {604, {{0.9078359604f, 0.4055104256f, 0.0418281555f, 0.0723958611f}, 1}},
      {612, {{0.1354218721f, 0.4391666651f, 0.0510937497f, 0.0851666629f}, 1}},
      {613, {{0.1354218721f, 0.4391666651f, 0.0510937497f, 0.0851666629f}, 1}},
      {1916, {{0.4388046861f, 0.3542187214f, 0.0972031355f, 0.0771458447f}, 26}},
      {1954, {{0.4388046861f, 0.3542187214f, 0.0972031355f, 0.0771458447f}, 26}},
      {2003, {{0.7474140525f, 0.3919791579f, 0.0750156641f, 0.1561667025f}, 1}},
      {2004, {{0.7474140525f, 0.3919791579f, 0.0750156641f, 0.1561667025f}, 1}},
      {2041, {{0.7474140525f, 0.3919791579f, 0.0750156641f, 0.1561667025f}, 1}},
      {2042, {{0.7474140525f, 0.3919791579f, 0.0750156641f, 0.1561667025f}, 1}},
      {2088, {{0.9620156288f, 0.4511666894f, 0.0759687424f, 0.1677500308f}, 1}},
      {2091, {{0.0516796894f, 0.4906562865f, 0.0873906240f, 0.1060208678f}, 1}},
      {2126, {{0.9620156288f, 0.4511666894f, 0.0759687424f, 0.1677500308f}, 1}},
      {2129, {{0.0516796894f, 0.4906562865f, 0.0873906240f, 0.1060208678f}, 1}},
      {2130, {{0.0516796894f, 0.4906562865f, 0.0873906240f, 0.1060208678f}, 1}},
      {3386, {{0.1115781218f, 0.3689270914f, 0.1526249945f, 0.0463541746f}, 26}},
      {3393, {{0.3334218860f, 0.3543125093f, 0.1565937698f, 0.0461666584f}, 26}},
      {3394, {{0.3334218860f, 0.3543125093f, 0.1565937698f, 0.0461666584f}, 26}},
      {3395, {{0.3334218860f, 0.3543125093f, 0.1565937698f, 0.0461666584f}, 26}},
      {3398, {{0.4388046861f, 0.3542187214f, 0.0972031355f, 0.0771458447f}, 26}},
      {3409, {{0.7204062343f, 0.3478437662f, 0.0764062405f, 0.0378958285f}, 26}},
      {3644, {{0.9293359518f, 0.5199896097f, 0.1236405969f, 0.0556041598f}, 48}},
      {3645, {{0.9293359518f, 0.5199896097f, 0.1236405969f, 0.0556041598f}, 48}},
      {4710, {{0.9763671756f, 0.2702083290f, 0.0472656488f, 0.0580833405f}, 26}},
      {4748, {{0.9763671756f, 0.2702083290f, 0.0472656488f, 0.0580833405f}, 26}},
      {4915, {{0.3596718609f, 0.4367812574f, 0.0600312352f, 0.1426874995f}, 1}},
      {4921, {{0.5105234385f, 0.4241041541f, 0.0394530892f, 0.0998750031f}, 1}},
      {4922, {{0.5469686985f, 0.4246770740f, 0.0412499905f, 0.0901874900f}, 1}},
      {4934, {{0.8764452934f, 0.4092812538f, 0.0236718655f, 0.0417291522f}, 27}},
      {4945, {{0.1354218721f, 0.4391666651f, 0.0510937497f, 0.0851666629f}, 1}},
      {4953, {{0.3596718609f, 0.4367812574f, 0.0600312352f, 0.1426874995f}, 1}},
      {4960, {{0.5469686985f, 0.4246770740f, 0.0412499905f, 0.0901874900f}, 1}},
      {4973, {{0.8965156078f, 0.4128749967f, 0.0105312467f, 0.0403333306f}, 27}},
      {4991, {{0.3596718609f, 0.4367812574f, 0.0600312352f, 0.1426874995f}, 1}},
      {4995, {{0.4654218554f, 0.4639999866f, 0.0356562436f, 0.0650416911f}, 27}},
      {5017, {{0.0516796894f, 0.4906562865f, 0.0873906240f, 0.1060208678f}, 1}},
      {5018, {{0.0516796894f, 0.4906562865f, 0.0873906240f, 0.1060208678f}, 1}},
      {5203, {{0.9448281527f, 0.5761458278f, 0.0199375153f, 0.0236250162f}, 48}},
      {5811, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {5812, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {6172, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {6173, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {6191, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {6229, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {6248, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {6252, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {6253, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {6254, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {6272, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {6273, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {6293, {{0.2660468817f, 0.4887395799f, 0.2466250062f, 0.2274791598f}, 1}},
      {6294, {{0.2660468817f, 0.4887395799f, 0.2466250062f, 0.2274791598f}, 1}},
      {6303, {{0.7955077887f, 0.4887708426f, 0.1584219337f, 0.3303333521f}, 1}},
      {6304, {{0.7955077887f, 0.4887708426f, 0.1584219337f, 0.3303333521f}, 1}},
      {6312, {{0.2660468817f, 0.4887395799f, 0.2466250062f, 0.2274791598f}, 1}},
      {6313, {{0.2660468817f, 0.4887395799f, 0.2466250062f, 0.2274791598f}, 1}},
      {6322, {{0.7955077887f, 0.4887708426f, 0.1584219337f, 0.3303333521f}, 1}},
      {6323, {{0.7955077887f, 0.4887708426f, 0.1584219337f, 0.3303333521f}, 1}},
      {6533, {{0.8885625005f, 0.0896458328f, 0.2228749990f, 0.1792916656f}, 26}},
      {6590, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {6599, {{0.3601406217f, 0.3051145971f, 0.1655000150f, 0.0712708235f}, 26}},
      {6609, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {7014, {{0.2003593743f, 0.4419062138f, 0.0823437572f, 0.1818124950f}, 1}},
      {7019, {{0.4268515706f, 0.4520103931f, 0.0629218817f, 0.1948958337f}, 1}},
      {7312, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {7327, {{0.6346484423f, 0.3075208068f, 0.3436093628f, 0.1388333142f}, 26}},
      {7331, {{0.8768593669f, 0.2687812746f, 0.2462812662f, 0.1497292072f}, 26}},
      {7717, {{0.2003593743f, 0.4419062138f, 0.0823437572f, 0.1818124950f}, 1}},
      {7736, {{0.2003593743f, 0.4419062138f, 0.0823437572f, 0.1818124950f}, 1}},
      {7741, {{0.4516875148f, 0.4595520496f, 0.0674062669f, 0.1730208099f}, 1}},
      {7760, {{0.4516875148f, 0.4595520496f, 0.0674062669f, 0.1730208099f}, 1}},
      {7953, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {7954, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {7973, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {7984, {{0.2660468817f, 0.4887395799f, 0.2466250062f, 0.2274791598f}, 1}},
      {8054, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8067, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8068, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8077, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8078, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8153, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8154, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8155, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8172, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {8173, {{0.1453359425f, 0.3603020906f, 0.2906718850f, 0.2275625020f}, 26}},
      {8353, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8354, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8549, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8550, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8574, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8575, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8593, {{0.2476249933f, 0.1537083238f, 0.4952499866f, 0.2775416672f}, 26}},
      {8599, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8600, {{0.6338593960f, 0.2965208590f, 0.4740312696f, 0.5015416741f}, 26}},
      {8604, {{0.4992187619f, 0.4322916865f, 0.9984375238f, 0.1729166806f}, 1}},
    },
    {
      {244, {{0.4294453263f, 0.1798349023f, 0.0179843903f, 0.0384433866f}, 41}},
      {245, {{0.4746484160f, 0.1809905618f, 0.0126718581f, 0.0482075512f}, 40}},
      {283, {{0.4569531083f, 0.1864622682f, 0.0114999712f, 0.0316037834f}, 42}},
      {551, {{0.5270937681f, 0.3901061416f, 0.0042500496f, 0.0242217183f}, 40}},
      {584, {{0.3869609237f, 0.4159433842f, 0.0717968941f, 0.0540094078f}, 69}},
      {589, {{0.5045781136f, 0.3968750238f, 0.0081562400f, 0.0306839645f}, 40}},
      {647, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {648, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {2091, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {2092, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {3472, {{0.3869609237f, 0.4159433842f, 0.0717968941f, 0.0540094078f}, 69}},
      {3508, {{0.3275234401f, 0.4494339526f, 0.1012343764f, 0.0314622521f}, 72}},
      {3536, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {4409, {{0.0297421888f, 0.0567924529f, 0.0246406179f, 0.0497641526f}, 41}},
      {4413, {{0.1393671930f, 0.0765330195f, 0.0199218839f, 0.0737264156f}, 41}},
      {4469, {{0.6299452782f, 0.1071933955f, 0.0167343616f, 0.0666037723f}, 40}},
      {4470, {{0.6457109451f, 0.1147169769f, 0.0173906088f, 0.0491981208f}, 40}},
      {4543, {{0.5828125477f, 0.1426886767f, 0.0187500119f, 0.0636792406f}, 40}},
      {4544, {{0.5894765854f, 0.1333490610f, 0.0090156198f, 0.0507547259f}, 40}},
      {4545, {{0.6148046255f, 0.1257665157f, 0.0114530921f, 0.0473349094f}, 40}},
      {4579, {{0.5206875205f, 0.1676886678f, 0.0069687366f, 0.0426886827f}, 41}},
      {4580, {{0.5515702963f, 0.1546698213f, 0.0132343769f, 0.0457547158f}, 41}},
      {4581, {{0.5564687252f, 0.1591273546f, 0.0050937533f, 0.0221226364f}, 41}},
      {4617, {{0.5270624757f, 0.1686202884f, 0.0131562948f, 0.0343160331f}, 41}},
      {4618, {{0.5438203216f, 0.1700589657f, 0.0082343817f, 0.0193632096f}, 41}},
      {4920, {{0.4976249635f, 0.4049174786f, 0.0075936913f, 0.0562028587f}, 40}},
      {4979, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {4980, {{0.0571015663f, 0.4673820436f, 0.0852656290f, 0.0785848498f}, 71}},
      {4997, {{0.5234765410f, 0.4760730863f, 0.0577968359f, 0.1289858520f}, 59}},
      {5035, {{0.5234765410f, 0.4760730863f, 0.0577968359f, 0.1289858520f}, 59}},
      {5037, {{0.5602656603f, 0.4951297045f, 0.0233125091f, 0.0566745102f}, 70}},
      {6355, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {6374, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {6393, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {6412, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8006, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8106, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8107, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8278, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8288, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8296, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8298, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8306, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8316, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8478, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8488, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8496, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8498, {{0.6676875353f, 0.4778419435f, 0.1911874413f, 0.5212499499f}, 73}},
      {8506, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
      {8516, {{0.5017108917f, 0.6921344399f, 0.2173593640f, 0.4314386845f}, 61}},
    },
    {
      {1865, {{0.0885468721f, 0.3239618540f, 0.0668750107f, 0.1490253955f}, 3}},
      {1903, {{0.0885468721f, 0.3239618540f, 0.0668750107f, 0.1490253955f}, 3}},
      {4640, {{0.1116015613f, 0.2488983124f, 0.0165156350f, 0.0305084884f}, 1}},
      {4772, {{0.5981093645f, 0.3173516691f, 0.0346562266f, 0.1462287754f}, 1}},
      {4810, {{0.5981093645f, 0.3173516691f, 0.0346562266f, 0.1462287754f}, 1}},
      {4811, {{0.6264609098f, 0.3457626998f, 0.0227343440f, 0.0977966189f}, 57}},
      {4848, {{0.6012890339f, 0.3552754521f, 0.0178906322f, 0.0375847518f}, 57}},
      {5416, {{0.5484218597f, 0.7589406967f, 0.0340625048f, 0.0901694894f}, 33}},
      {7747, {{0.7934843898f, 0.3799364567f, 0.0628750324f, 0.5124152899f}, 1}},
      {7827, {{0.9749140143f, 0.5235804915f, 0.0455781221f, 0.7370762825f}, 1}},
      {8482, {{0.0454609357f, 0.4749576151f, 0.0903281346f, 0.7714406848f}, 1}},
      {8483, {{0.1402656287f, 0.5571609735f, 0.1210937500f, 0.7041524649f}, 1}},
      {8486, {{0.4599062204f, 0.4550423622f, 0.1010937393f, 0.6179660559f}, 1}},
      {8487, {{0.5440546870f, 0.4932415187f, 0.1175155938f, 0.5445339084f}, 1}},
      {8488, {{0.6667343378f, 0.5011864901f, 0.1146562696f, 0.5350000262f}, 1}},
      {8493, {{0.1402656287f, 0.5571609735f, 0.1210937500f, 0.7041524649f}, 1}},
    }
  };

  // Offsets matching the above dict, with mean [0,0,0,0] stds [0.1, 0.1, 0.2, 0.2] scale 300
  const vector<vector<float4>> coco_offsets = {
    {
      {0.6532719135f, -0.3399074376f, 1.96442616f, -1.768630266f},
      {1.305068731f, 0.939853549f, -0.482365489f, 1.288143873f},
      {-0.3697855771f, 3.001256227f, 0.1732979566f, 2.610199213f},
      {-0.5442733169f, -0.01566567831f, 0.2215743959f, 2.116333246f},
      {-0.3697855771f, -0.8082647324f, 0.1732979566f, 2.610199213f},
      {1.858628035f, -0.4793149233f, 0.6500419378f, -0.7670986652f},
      {-1.950892925f, -0.4793149233f, 0.6500419378f, -0.7670986652f},
      {0.8915318251f, 0.6420422792f, -2.387714624f, -0.6172055006f},
      {-1.710871935f, 0.6420422792f, -2.387714624f, -0.6172055006f},
      {-0.2526116967f, 2.050248623f, -1.732051373f, 0.7048498988f},
      {2.230589867f, -0.01070169732f, -1.683773279f, 0.210984081f},
      {-0.3718095124f, -0.01070169732f, -1.683774829f, 0.210984081f},
      {2.349792004f, -0.5521500111f, -1.732051373f, 0.7048498988f},
      {-0.2526116967f, -0.5521500111f, -1.732051373f, 0.7048498988f},
      {0.4619332254f, -0.480701983f, 0.231561318f, -0.03575952351f},
      {-2.231806278f, -0.480701983f, 0.231561318f, -0.03575952351f},
      {1.314249277f, -0.6778535247f, -1.082823396f, 0.9657678604f},
      {-1.379490376f, -0.6778535247f, -1.082823396f, 0.9657678604f},
      {1.459985852f, -3.51448822f, -2.947214603f, 2.763273954f},
      {1.845646977f, 0.6645771861f, 1.25050509f, -0.4447214007f},
      {-0.7697191834f, -0.01107731368f, 1.954445243f, 0.3834679723f},
      {-0.5229560733f, -0.5715298057f, 1.90616858f, 0.8773342967f},
      {-0.6265667081f, 1.067986488f, 1.412954569f, 1.436766982f},
      {1.974726558f, 0.7200363874f, -0.558188498f, -0.534376204f},
      {-0.4224309623f, 0.7200363874f, -0.5581908226f, -0.534376204f},
      {-0.4224309623f, -1.677120566f, -0.5581908226f, -0.5343785286f},
      {-0.4430495799f, 1.510361075f, -0.3199130893f, 3.169635296f},
      {-0.4430495799f, -3.517959595f, -0.3199130893f, 3.169635296f},
      {-2.362583876f, 0.1442723572f, -0.1345866024f, 1.176138878f},
      {-2.901610374f, -0.301014185f, 2.155317307f, 0.5522986054f},
      {-2.893562555f, 0.1177978963f, 0.8790759444f, 0.1624761075f},
      {0.9839975238f, 0.09773068875f, -2.102617979f, 1.787424922f},
      {0.876311779f, 0.08703540266f, -2.682121992f, 1.207921386f},
      {1.391582131f, 0.06910603493f, -0.3697502315f, 0.05455720797f},
      {-1.063061595f, 0.4482340813f, -1.645991206f, -0.3352654278f},
      {-0.8431178331f, 0.4373901188f, -2.804999113f, -0.4577156603f},
    },
    {
      {0.7473967075f, 0.2936508358f, -2.839264631f, 0.9182167649f},
      {1.583553433f, 0.6356889606f, -0.3057855368f, 0.5707916617f},
      {-1.01884532f, 0.6356889606f, -0.3057855368f, 0.5707916617f},
      {1.583553433f, -1.966710567f, -0.3057855368f, 0.5707916617f},
      {-1.01884532f, -1.966710567f, -0.3057855368f, 0.5707916617f},
      {1.056979179f, 0.2076424956f, -1.106393814f, -0.8146509528f},
      {-1.991884112f, -1.589589357f, -4.770983219f, -4.363641739f},
      {-2.024507523f, 0.6341558099f, -2.17605114f, -1.061738968f},
      {-1.567326784f, -0.6102954149f, -6.849811077f, -5.046186924f},
      {2.352295399f, 0.2328907549f, -2.495825052f, 1.553084731f},
      {3.416513681f, -0.7638908625f, 2.164221287f, 0.4029771388f},
      {-0.7664937973f, -0.7638908625f, 2.164221287f, 0.4029771388f},
      {2.937269211f, -0.6567376852f, 1.408519745f, -0.3527241647f},
      {-0.6589755416f, -0.6567376852f, 1.408519745f, -0.3527241647f},
      {-0.5419929624f, -1.080304861f, 0.4313528538f, 2.135845423f},
      {-0.08344639838f, -0.0815224722f, 0.6528166533f, -1.108427405f},
      {-0.07431432605f, -0.07260094583f, 0.07331302017f, -1.687930822f},
      {-0.05900552124f, -0.1152901873f, -1.080051064f, 0.6244407296f},
      {-0.06618163735f, -0.06465575844f, -0.506190896f, -2.267435074f},
      {-0.0575780198f, -0.09143704176f, -1.202501297f, -0.5345672369f},
    },
    {
      {2.344197512f, -0.1112225205f, 2.704902887f, -0.9490292668f},
      {-0.2558816075f, -0.1112225205f, 2.704902172f, -0.9490292668f},
      {-2.855961561f, -0.1112225205f, 2.704902887f, -0.9490292668f},
      {0.8864489198f, 2.567617893f, -0.1292492151f, 1.726831794f},
      {0.8864489198f, 0.2820203304f, -0.1292492151f, 1.726832271f},
      {0.8864489198f, -2.003577232f, -0.1292492151f, 1.726832271f},
      {1.085673571f, 2.096451044f, 0.8844130635f, 0.7131687403f},
      {-2.755124331f, 0.4287824333f, 1.724333405f, 1.343361378f},
      {1.085673571f, 0.2302686423f, 0.8844130635f, 0.7131692171f},
      {1.085673571f, -1.635914326f, 0.8844130635f, 0.7131696939f},
      {0.8399205804f, -1.135218978f, 1.616607308f, -2.037323713f},
      {0.7221024632f, -0.9759781957f, 0.8609058857f, -2.793027163f},
      {0.5939134359f, -1.605442166f, -0.1162610874f, -0.3044557273f},
      {2.052499533f, -0.5569749475f, -2.305838823f, -0.4497586489f},
      {0.4849283397f, -1.966257095f, -1.129923344f, 0.7092067599f},
    },
    {
      {-0.2149030566f, 1.890320659f, 0.7271362543f, 0.5510314107f},
      {2.182251692f, -0.5068340898f, 0.727135241f, 0.5510324836f},
      {-0.2149030566f, -0.5068340898f, 0.7271362543f, 0.5510324836f},
      {-2.612057209f, -0.5068340898f, 0.7271347046f, 0.5510324836f},
      {-0.2149030566f, -2.903988361f, 0.7271362543f, 0.5510308743f},
      {-1.423295617f, 0.6149251461f, -0.3771707118f, 1.311205268f},
      {-1.423295617f, -1.899232507f, -0.3771707118f, 1.311207056f},
      {-0.07758918405f, 2.235767126f, -0.7403200269f, 0.6156871915f},
      {-0.07758918405f, -0.2783906162f, -0.7403200269f, 0.6156845093f},
      {-0.07758918405f, -2.792548895f, -0.7403200269f, 0.6156871915f},
      {-1.743173838f, 0.5020842552f, 0.6364920735f, 0.297542125f},
      {-1.743173838f, -1.550716639f, 0.6364920735f, 0.2975432277f},
      {-0.09502690285f, 1.825496078f, 0.273339957f, -0.3979759514f},
      {-0.09502690285f, -0.2273049504f, 0.273339957f, -0.3979785442f},
      {-0.09502690285f, -2.280106306f, 0.273339957f, -0.3979759514f},
      {-0.9529682398f, -1.149788141f, -1.244008303f, -1.420111895f},
      {-0.4576793313f, 2.076341391f, -1.027064085f, 0.2036268264f},
      {0.5272055864f, 1.582555294f, -1.873074412f, 0.2425000072f},
      {2.346530437f, -0.2052420378f, -3.451726437f, 0.3273487687f},
      {-0.4576793313f, -0.2092559785f, -1.027064085f, 0.2036273777f},
      {0.5272055864f, -0.7030422688f, -1.873074412f, 0.2425005585f},
      {-0.4576793313f, -2.494853735f, -1.027064085f, 0.2036273777f},
      {-0.5605403781f, 1.695325613f, -0.01340187062f, -0.8100363612f},
      {0.6456923485f, 1.292150855f, -0.8594122529f, -0.7711633444f},
      {-0.5605403781f, -0.1708567888f, -0.01340187062f, -0.8100360036f},
      {0.6456923485f, -0.5740315914f, -0.8594122529f, -0.7711625695f},
      {-0.5605403781f, -2.037039757f, -0.01340187062f, -0.8100349307f},
      {0.6456923485f, -2.440214634f, -0.8594122529f, -0.7711619139f},
    },
    {
      {-1.925592422f, 1.345238328f, -2.747560024f, -1.01626718f},
      {0.2659557462f, 1.64991343f, -11.30098248f, -3.038144588f},
      {-1.104854107f, 0.6608059406f, -2.370016575f, -0.06328167021f},
      {-1.801437974f, 0.2304451168f, -4.140355587f, -1.530188322f},
      {0.4408884048f, -0.8333674669f, -5.473905563f, -1.700235844f},
      {-1.654131651f, -2.436998844f, -6.554378986f, -5.785286903f},
      {1.759345651f, -0.9480711222f, -3.273507595f, -0.736420989f},
      {0.1031176671f, -0.7470867038f, -5.306909084f, -3.373731852f},
      {-0.04366187751f, -0.9649028778f, -3.252289534f, -4.63355732f},
      {0.9216972589f, 1.658264995f, -2.192988396f, 0.915779531f},
      {0.9216972589f, -0.8558925986f, -2.192988396f, 0.9157770872f},
      {1.128843784f, 1.353967428f, -1.179326057f, -0.09788365662f},
      {1.128843784f, -0.698833406f, -1.179326057f, -0.09788609296f},
      {-0.1241042838f, 1.276496053f, -1.501559138f, 0.2862437665f},
      {-0.1241042838f, -1.009101748f, -1.501559138f, 0.2862443328f},
      {-0.1519960463f, 1.042254806f, -0.4878975451f, -0.7274180651f},
      {-0.1519960463f, -0.8239281178f, -0.4878975451f, -0.7274180651f},
      {-0.1519960463f, -2.69011116f, -0.4878975451f, -0.7274180651f},
    },
    {
      {0.8563995957f, -2.058098316f, -7.925899982f, -6.165257454f},
      {1.084333301f, -0.5567326546f, 0.028581433f, -0.8028960824f},
      {-1.609401584f, -0.5567326546f, 0.02858261764f, -0.8028960824f},
      {-1.194294691f, -0.5271564126f, -6.280949593f, -3.222279787f},
      {-2.4759233f, -0.4999512434f, -3.955951214f, -2.646148682f},
      {-0.4745673239f, -2.033315659f, -5.34355402f, -3.901858807f},
      {1.024877548f, -2.519467831f, -5.896973133f, -4.952185154f},
      {1.481030703f, -2.090093374f, -7.484749317f, -12.24684429f},
      {-3.509741068f, -1.357121587f, -6.70290947f, -12.81184578f},
      {-1.729889989f, 3.285559654f, -5.876472473f, -12.5576973f},
      {0.8623040915f, 2.3002491f, -7.484749317f, -12.78126717f},
      {-1.136935234f, 1.04878962f, -7.627824306f, -12.72066593f},
      {1.318457246f, 2.753275633f, -6.660890579f, -11.41580009f},
      {-2.033457756f, 0.7045835853f, -6.583734512f, -12.70561409f},
      {-2.37597084f, -0.546474874f, -4.779187679f, -6.474086761f},
      {-0.8075972795f, 3.075801611f, 0.2360822558f, 2.51555562f},
      {0.5540198088f, 0.9916225076f, -2.392875433f, 0.7212347984f},
      {-0.8075972795f, 0.3820594251f, 0.2360822558f, 2.51555562f},
      {-1.315831661f, 1.994278669f, -0.2838667333f, 0.4140156209f},
      {-0.8075972795f, -2.311677694f, 0.2360822558f, 2.51555562f},
      {-1.315831661f, -0.6994583607f, -0.2838667333f, 0.4140156209f},
      {-2.607983589f, -3.873429775f, -1.681791067f, 3.036060095f},
      {2.173928022f, 0.5216356516f, -2.916009903f, -1.096045136f},
      {1.69158709f, 1.18138361f, -1.743091941f, 1.335167289f},
      {-0.7055676579f, 1.18138361f, -1.743089795f, 1.335167289f},
      {1.69158709f, -1.215771437f, -1.743091941f, 1.3351686f},
      {-0.7055676579f, -1.215771437f, -1.743089795f, 1.3351686f},
      {1.385733604f, -1.126014709f, 2.261646509f, -1.714755416f},
      {-1.846589088f, -1.126014709f, 2.261646509f, -1.714755416f},
      {0.9798618555f, -1.592425108f, 0.5287792087f, 0.01811200194f},
      {-1.305735946f, -1.592425108f, 0.5287797451f, 0.01811200194f},
      {-0.6536508799f, -0.8134405017f, -2.432554722f, -0.5814390779f},
      {0.5758612156f, 0.4433520138f, -2.600352049f, -1.228363276f},
      {0.8000538945f, -1.950314522f, -0.4848828018f, 1.031775117f},
      {-1.066128969f, -1.950314522f, -0.4848828018f, 1.031775117f},
      {-0.8005555868f, 1.202011108f, -1.418892264f, -1.595102549f},
      {-0.8005555868f, -0.6641713381f, -1.418892264f, -1.595102072f},
      {0.0f, -1.646132469f, 1.839668393f, -0.5111208558f},
      {0.0f, -1.465985656f, 1.260164976f, -1.090624213f},
      {0.0f, -2.327982903f, 0.1068005785f, 1.221747518f},
      {0.0f, -1.305553436f, 0.6806610227f, -1.670128107f},
      {0.0f, -1.188391685f, 0.2105303705f, -2.140258551f},
      {0.0f, -1.846331358f, -0.01564952359f, 0.06273975223f},
    },
    {
      {0.4334077537f, -1.398809671f, -1.963556528f, -0.9330812097f},
      {-0.1707603931f, -0.825900197f, 1.641538978f, 0.4860126972f},
      {-1.737713218f, -1.117557406f, -2.574631214f, 0.1682697833f},
      {2.203123569f, -0.1190476269f, -1.574165702f, 0.9805744886f},
      {-1.606400013f, -0.1190476269f, -1.574164748f, 0.9805744886f},
      {-0.1166515499f, 2.038205624f, -0.2638111413f, -1.419337511f},
      {-0.1166515499f, -0.5641972423f, -0.2638111413f, -1.419337511f},
      {1.374135733f, 0.5184469223f, -1.559344172f, 2.106794119f},
      {-1.228263021f, 0.5184469223f, -1.559344172f, 2.106794119f},
      {1.374135733f, -2.083953381f, -1.559344172f, 2.106794119f},
      {-1.228263021f, -2.083953381f, -1.559344172f, 2.106794119f},
      {-1.104499221f, 1.089757085f, -1.496216059f, 2.464548826f},
      {1.139820933f, 2.341146708f, -0.7958868742f, 0.1703538895f},
      {-1.104499221f, -1.512643218f, -1.496216059f, 2.464548826f},
      {1.139820933f, -0.2612535357f, -0.7958868742f, 0.1703521609f},
      {-1.462579489f, -0.2612535357f, -0.7958868742f, 0.1703521609f},
      {-0.8507375121f, 1.80354178f, 2.164574862f, -0.3280526102f},
      {2.702684641f, -1.149050355f, 2.292929649f, -0.3483198285f},
      {0.008945085108f, -1.149050355f, 2.292929649f, -0.3483198285f},
      {-2.684797049f, -1.149050355f, 2.292929649f, -0.3483198285f},
      {-0.1207458004f, -1.16799891f, -0.09133037925f, 2.218879223f},
      {-1.305833459f, -2.455937147f, -1.295023441f, -1.335403919f},
      {0.9430719018f, -0.002096263459f, 1.111549377f, 0.5816810727f},
      {-1.750667691f, -0.002096263459f, 1.111549377f, 0.5816810727f},
      {0.6129309535f, 1.704632282f, -0.2306900918f, -2.665949345f},
      {0.6129309535f, -0.9891076088f, -0.2306900918f, -2.665949345f},
      {-0.06629946828f, 2.368597746f, 0.9647157788f, 1.827939749f},
      {-1.914556503f, 1.088017225f, -1.13404727f, 0.04425197467f},
      {0.06101770699f, 1.145890594f, -0.9113547206f, -0.465891391f},
      {1.975584507f, -0.4093210995f, -3.688173056f, -4.319345474f},
      {-2.271792412f, -0.08417935669f, 0.1587023437f, -0.7522946596f},
      {-0.06629946828f, -0.3251417577f, 0.9647157788f, 1.827939749f},
      {0.06101770699f, -1.547849059f, -0.9113547206f, -0.465891391f},
      {0.6429157853f, -2.740039825f, -7.737875462f, -4.489454269f},
      {-0.06629946828f, -3.018876791f, 0.9647157788f, 1.827940941f},
      {-0.2514899373f, -0.26936993f, -1.639987946f, -2.100201607f},
      {2.35965395f, -0.2704231143f, 2.842332125f, 0.3428347409f},
      {-3.027827978f, -0.2704231143f, 2.842332125f, 0.3428347409f},
      {-0.3714290857f, -2.409634352f, -4.546593189f, -7.163814068f},
      {0.5708348155f, 0.6430553794f, 1.979879856f, 0.8918926716f},
      {-2.984721422f, 0.6430553794f, 1.979879856f, 0.8918926716f},
      {0.3848565817f, 0.4335478246f, 0.008734579198f, -1.079250693f},
      {-2.012298822f, 0.4335478246f, 0.008736959659f, -1.079250693f},
      {0.3848565817f, -1.963607669f, 0.008734579198f, -1.079250693f},
      {-0.1411623806f, 1.293623567f, 0.5080496073f, -1.980177402f},
      {-0.1411623806f, -1.103532672f, 0.5080496073f, -1.980178356f},
      {2.936632395f, 0.6128670573f, 1.336655736f, 0.1128047481f},
      {0.5394768119f, 0.6128670573f, 1.336655736f, 0.1128047481f},
      {-1.857677579f, 0.6128670573f, 1.336655736f, 0.1128047481f},
      {0.5394768119f, -1.78428793f, 1.336655736f, 0.1128047481f},
      {-1.857677579f, -1.78428793f, 1.336655736f, 0.1128047481f},
      {1.170721412f, 1.59139204f, 0.5150253177f, 0.1109734178f},
      {-1.226434827f, 1.59139204f, 0.5150247812f, 0.1109734178f},
      {0.996668458f, 1.592798114f, -1.698011279f, 1.976191521f},
      {-1.400486708f, 1.592798114f, -1.698009253f, 1.976191521f},
      {1.170721412f, -0.8057627678f, 0.5150253177f, 0.1109728292f},
      {-1.226434827f, -0.8057627678f, 0.5150247812f, 0.1109728292f},
      {0.996668458f, -0.804356873f, -1.698011279f, 1.976190805f},
      {-1.400486708f, -0.804356873f, -1.698009253f, 1.976190805f},
      {0.4036411643f, 0.9094176292f, 0.2470121831f, 2.624760628f},
      {-0.1480524242f, 2.713525295f, 0.7463279366f, 1.723833561f},
      {0.6351677179f, 1.110747695f, -1.24118793f, -1.98787415f},
      {-0.1480524242f, -2.314789295f, 0.7463279366f, 1.723832369f},
      {1.290960431f, -0.5386788249f, -1.265795469f, -0.7711650133f},
      {-2.496725321f, -0.06236385182f, -2.610840082f, -0.423718214f},
      {-0.1208842918f, 3.32337594f, -0.2673354745f, 2.737495899f},
      {-1.232381701f, 1.638227344f, 1.397818208f, 2.359722853f},
      {-0.1208842918f, -2.835026026f, -0.2673354745f, 2.737494707f},
      {1.581097126f, 1.612971425f, -0.2521326244f, -1.784828186f},
      {1.581097126f, -0.4398293793f, -0.2521326244f, -1.784828186f},
      {-0.1900420487f, 0.239358604f, -1.252957463f, -2.032648325f},
      {-0.1900420487f, -1.813442349f, -1.252957463f, -2.032647371f},
      {2.65530324f, -0.1906570345f, 2.029850483f, -0.8656078577f},
      {-0.5770211816f, -0.1906570345f, 2.029850483f, -0.8656078577f},
      {-0.444365263f, -0.394885838f, -0.6344873905f, -1.85833931f},
      {-0.01878218353f, 0.2648355663f, -1.456118107f, -1.860169411f},
      {-0.4641556442f, -0.1533644497f, 0.941554904f, -1.95390296f},
      {1.1503582f, 0.7277178764f, 0.7226076722f, 1.004675269f},
      {-1.449721336f, 0.7277178764f, 0.7226076722f, 1.004675269f},
      {1.1503582f, -1.872361183f, 0.7226076722f, 1.004674911f},
      {-1.449721336f, -1.872361183f, 0.7226076722f, 1.004674911f},
      {1.877582669f, -0.2696297467f, 0.2969821692f, 0.8672597408f},
      {-0.4080155492f, -0.2696297467f, 0.2969821692f, 0.8672597408f},
      {-2.693612337f, -0.2696297467f, 0.2969816029f, 0.8672597408f},
      {1.97138381f, -0.5584529042f, -2.367355585f, -0.1254709065f},
      {-0.3142136633f, -0.5584529042f, -2.367355585f, -0.1254709065f},
      {1.533039808f, -0.3302276433f, -0.7166810036f, 1.880922794f},
      {-0.3331432939f, -0.3302276433f, -0.7166810036f, 1.880922794f},
      {1.971098423f, -0.4603751004f, -0.3656870425f, -0.08362001926f},
      {-2.21190691f, -0.4603751004f, -0.3656870425f, -0.08362001926f},
      {1.694606662f, -0.3957969546f, -1.121388555f, -0.8393213749f},
      {-1.901636004f, -0.3957969546f, -1.121389985f, -0.8393213749f},
      {-1.003467679f, 1.304449677f, -1.87960875f, -1.309330583f},
      {1.393777013f, -0.651068747f, -2.098555565f, 1.649248123f},
      {-1.564054608f, -0.651068747f, -2.09855485f, 1.649248123f},
      {-0.4729938507f, -2.801854372f, 1.62603581f, -3.675136328f},
    },
    {
      {-1.507808208f, 0.9287953377f, -6.7949543f, -2.996542215f},
      {1.140253067f, 1.093889952f, -8.545557022f, -1.864897609f},
      {-1.387648821f, -1.933962703f, -9.030753136f, -3.976091385f},
      {1.013393879f, 0.4913548231f, -14.0078249f, -5.306227207f},
      {0.04203796759f, 0.3728630841f, 0.1267305315f, -1.296684742f},
      {-2.203128338f, -2.351186991f, -10.74856186f, -4.123774529f},
      {2.443080902f, 0.1021975651f, 0.9863803983f, 0.5784190297f},
      {-1.366443515f, 0.1021975651f, 0.9863803983f, 0.5784190297f},
      {1.668941855f, 0.06981422752f, -0.9189697504f, -1.326931357f},
      {-0.9334585667f, 0.06981422752f, -0.9189697504f, -1.326931357f},
      {0.0297253225f, 0.527307868f, -1.606139183f, 0.4361819029f},
      {-0.5868869424f, 1.90594542f, 0.1118471995f, -2.265666485f},
      {-0.9662215114f, 0.1445291489f, -0.7464873195f, 2.311285496f},
      {-2.072390795f, -0.9974470735f, -3.487626791f, -3.438869953f},
      {-1.474716306f, 0.9966513515f, -4.550514221f, -1.473538876f},
      {0.6623781323f, 1.400078177f, -5.422287941f, -1.98153758f},
      {-1.539941907f, 2.160073996f, -5.229957104f, -3.49606657f},
      {1.915090799f, -0.4018378556f, -4.853636742f, -2.206050396f},
      {-2.126052856f, -1.345281243f, -8.514816284f, -3.340319872f},
      {-2.396491528f, -2.111234426f, -7.318310261f, -3.689103365f},
      {0.1388980001f, -0.5701979399f, -9.802438736f, -4.205674648f},
      {0.9906796813f, -1.885299206f, -6.595520496f, -3.858869553f},
      {-3.40716815f, -1.435021162f, -11.36953449f, -7.492337227f},
      {1.426836133f, -3.169829845f, -6.625107288f, -5.297280312f},
      {-0.5750440955f, -3.024501801f, -8.968017578f, -8.1584692f},
      {0.8670412898f, -0.8501298428f, -9.373020172f, -2.83050704f},
      {3.455038548f, 0.07226973027f, 2.71924901f, -1.154448986f},
      {-1.932443261f, 0.07226973027f, 2.71924901f, -1.154448986f},
      {0.7023715973f, 0.9501984715f, 0.7750607729f, 1.323169708f},
      {0.7023715973f, -1.743546605f, 0.7750607729f, 1.323168397f},
      {-2.640069008f, 0.1814603806f, -3.764658928f, -2.788722277f},
      {-0.2227443457f, 3.541846037f, -0.1165603399f, 3.311306f},
      {-0.2227443457f, 1.144691944f, -0.1165603399f, 3.311308384f},
      {-0.2227443457f, -1.252465248f, -0.1165603399f, 3.311306f},
      {-0.2227443457f, -3.649617434f, -0.1165603399f, 3.311306f},
      {0.6579065919f, -0.0363297835f, -2.087702751f, 1.34016335f},
      {0.5292198062f, -0.02922366746f, -3.175997734f, 0.2518683374f},
      {-2.070859671f, -0.02922366746f, -3.175998211f, 0.2518683374f},
      {-1.099049687f, 2.239355803f, -0.99632442f, 0.5528168082f},
      {-1.099049687f, -0.04624158144f, -0.99632442f, 0.5528173447f},
      {0.9304205179f, 2.259908676f, -0.3548343778f, -0.3927039802f},
      {-1.099049687f, -2.331839323f, -0.99632442f, 0.5528173447f},
      {0.9304205179f, -0.02568904124f, -0.3548343778f, -0.3927039802f},
      {0.9304205179f, -2.311286926f, -0.3548343778f, -0.3927033246f},
      {-1.34605515f, 1.828426361f, 0.0173375085f, -0.4608463943f},
      {-1.34605515f, -0.03775609285f, 0.0173375085f, -0.4608457088f},
      {1.139527559f, 1.84520793f, 0.6588275433f, -1.40636611f},
      {-1.34605515f, -1.903939128f, 0.0173375085f, -0.4608450532f},
      {1.139527559f, -0.02097501606f, 0.6588275433f, -1.40636611f},
      {1.139527559f, -1.887158036f, 0.6588275433f, -1.40636611f},
    },
    {
      {-0.4671106339f, 1.687836528f, -2.133699179f, 1.872757673f},
      {-0.4671106339f, -0.9145638943f, -2.133699179f, 1.872757673f},
      {-1.696740627f, 2.245735884f, -5.488070011f, -5.885319233f},
      {-0.3819617927f, 1.079347014f, -1.782221913f, 1.950516582f},
      {-0.3819617927f, -1.614392519f, -1.782221913f, 1.950516582f},
      {-0.04156561568f, 1.255556464f, -3.890225649f, -0.06089515612f},
      {0.2604196072f, -0.4772544503f, -5.08822298f, -4.842352867f},
      {0.3545973301f, -0.1070070565f, -1.86862278f, -0.4668895602f},
      {2.3268435f, -2.825047255f, -1.600901484f, 3.395969629f},
      {-1.357076645f, -5.507388115f, -3.209504843f, 5.213747501f},
      {-0.4131940305f, -0.08821856976f, -3.731687546f, 1.499304771f},
      {-1.035785794f, 1.349966526f, -2.266107082f, 1.042980433f},
      {-1.054650426f, -0.4366452992f, -3.168691397f, 0.3901735544f},
      {-2.236549616f, 0.2316666245f, -2.416078806f, -0.2423432618f},
      {-1.396085858f, 0.3706671298f, -2.53924036f, -0.3306598961f},
      {-1.035785794f, -0.5162162185f, -2.266107082f, 1.042981386f},
    }
  };


  const int coco_anchors_count_ = 8732;

  inline float Clamp(float val) { return val > 1.f ? 1.f : (val < 0.f ? 0.f : val); }

  // Creates SSD default boxes (anchors) for COCO dataset.
  // Exact description can be found in https://arxiv.org/abs/1512.02325
  void CreateCocoAnchors() {
    anchors_ = vector<float>(coco_anchors_count_ * 4);

    int fig_size = 300;
    vector<int> feat_sizes {38, 19, 10, 5, 3, 1};
    int feat_count = feat_sizes.size();
    vector<float> steps {8.f, 16.f, 32.f, 64.f, 100.f, 300.f};
    vector<float> scales {21.f, 45.f, 99.f, 153.f, 207.f, 261.f, 315.f};
    vector<vector<int>> aspect_ratios {{2}, {2, 3}, {2, 3}, {2, 3}, {2}, {2}};

    vector<float> fks;
    for (auto &step : steps) fks.push_back(fig_size / step);

    int anchor_idx = 0;
    for (int idx = 0; idx < feat_count; ++idx) {
      auto sk1 = scales[idx] / fig_size;
      auto sk2 = scales[idx + 1] / fig_size;
      auto sk3 = std::sqrt(sk1 * sk2);
      vector<std::pair<float, float>> all_sizes{{sk1, sk1}, {sk3, sk3}};

      for (auto &alpha : aspect_ratios[idx]) {
        auto w = sk1 * sqrt(alpha);
        auto h = sk1 / sqrt(alpha);
        all_sizes.push_back({w, h});
        all_sizes.push_back({h, w});
      }

      for (auto &sizes : all_sizes) {
        auto w = sizes.first;
        auto h = sizes.second;

        for (int i = 0; i < feat_sizes[idx]; ++i)
          for (int j = 0; j < feat_sizes[idx]; ++j) {
            auto cx = (j + 0.5f) / fks[idx];
            auto cy = (i + 0.5f) / fks[idx];

            cx = this->Clamp(cx);
            cy = this->Clamp(cy);
            w = this->Clamp(w);
            h = this->Clamp(h);

            anchors_[anchor_idx * 4] = cx - 0.5f * w;
            anchors_[anchor_idx * 4 + 1] = cy - 0.5f * h;
            anchors_[anchor_idx * 4 + 2] = cx + 0.5f * w;
            anchors_[anchor_idx * 4 + 3] = cy + 0.5f * h;

            ++anchor_idx;
          }
      }
    }
  }

  void CheckAnswersForCoco(TensorList<CPUBackend> *boxes,
                           TensorList<CPUBackend> *labels,
                           bool offset) {
    auto boxes_shape = boxes->shape();
    ASSERT_EQ(boxes_shape.size(), coco_batch_size);
    for (int i = 0; i < boxes_shape.size(); i++) {
      ASSERT_EQ(boxes_shape[i].size(), 2);
      ASSERT_EQ(boxes_shape[i][0], coco_anchors_count_);
      ASSERT_EQ(boxes_shape[i][1], 4);
    }

    auto labels_shape = labels->shape();
    ASSERT_EQ(labels_shape.size(), coco_batch_size);
    for (int i = 0; i < labels_shape.size(); i++) {
      ASSERT_EQ(labels_shape[i].size(), 1);
      ASSERT_EQ(labels_shape[i][0], coco_anchors_count_);
    }

    vector<float4> boxes_data(coco_anchors_count_);
    vector<int> labels_data(coco_anchors_count_);
    auto anchors_data = reinterpret_cast<float4 *>(anchors_.data());

    for (int sample = 0; sample < coco_batch_size; ++sample) {
      MemCopy(
        boxes_data.data(),
        boxes->tensor<float>(sample),
        coco_anchors_count_ * 4 * sizeof(float));
      MemCopy(labels_data.data(), labels->tensor<int>(sample), coco_anchors_count_ * sizeof(int));

      int idx = 0;
      for (size_t i = 0; i < coco_matches[sample].size(); ++i) {
        auto match = coco_matches[sample][i];
        while (idx < match.first) {
          ASSERT_EQ(labels_data[idx], 0);
          ++idx;
        }

        auto actual = boxes_data[match.first];
        auto expected = offset ? coco_offsets[sample][i] : match.second.first;

        ASSERT_EQ(labels_data[match.first], match.second.second);

        if (!offset) {
          ASSERT_FLOAT_EQ(actual.x, expected.x);
          ASSERT_FLOAT_EQ(actual.y, expected.y);
        } else {
          ASSERT_NEAR(actual.x, expected.x, 0.00001);
          ASSERT_NEAR(actual.y, expected.y, 0.00001);
        }
        ASSERT_FLOAT_EQ(actual.z, expected.z);
        ASSERT_FLOAT_EQ(actual.w, expected.w);
        ++idx;
      }

      while (idx < coco_anchors_count_) {
        ASSERT_EQ(labels_data[idx], 0);
        ++idx;
      }
    }
  }

  void CheckAnswersForCocoOnCpu(DeviceWorkspace *ws, bool offset = false) {
    TensorList<CPUBackend> &boxes = ws->Output<dali::CPUBackend>(0);
    TensorList<CPUBackend> &labels = ws->Output<dali::CPUBackend>(1);
    CheckAnswersForCoco(&boxes, &labels, offset);
  }

  void CheckAnswersForCocoOnGpu(DeviceWorkspace *ws, bool offset = false) {
    auto boxes = this->CopyTensorListToHost(ws->Output<dali::GPUBackend>(0));
    auto labels = this->CopyTensorListToHost(ws->Output<dali::GPUBackend>(1));
    CheckAnswersForCoco(boxes.get(), labels.get(), offset);
  }
};

typedef ::testing::Types<RGB, BGR, Gray> Types;
TYPED_TEST_SUITE(BoxEncoderTest, Types);

TYPED_TEST(BoxEncoderTest, TestOnCocoObjects) {
  this->RunForCocoCpu(this->anchors_, 0.5f);
}

TYPED_TEST(BoxEncoderTest, TestOffsetOnCocoObjects) {
  this->RunForCocoCpu(this->anchors_, 0.5f, true);
}

TYPED_TEST(BoxEncoderTest, TestOnCocoObjectsOnGpu) {
  this->RunForCocoGpu(this->anchors_, 0.5f);
}

TYPED_TEST(BoxEncoderTest, TestOffsetOnCocoObjectsGpu) {
  this->RunForCocoGpu(this->anchors_, 0.5f, true);
}

TYPED_TEST(BoxEncoderTest, TestNegativeCriteria) {
  EXPECT_THROW(this->RunForCocoCpu(this->anchors_, -0.5f), std::runtime_error);
}

TYPED_TEST(BoxEncoderTest, TestCriteriaOverOne) {
  EXPECT_THROW(this->RunForCocoCpu(this->anchors_, 1.5f), std::runtime_error);
}

TYPED_TEST(BoxEncoderTest, TestInvalidAnchors) {
  vector<float> invalid_anchors(this->anchors_);
  invalid_anchors.pop_back();

  EXPECT_THROW(this->RunForCocoCpu(invalid_anchors, 0.5f), std::runtime_error);
}

}  // namespace dali
